package mmc.cell3;

import java.util.Random;

class HeightMap{
	float[][] data;
	
	public HeightMap(int size, Random r){
		data = new float[size][size];
		
		for(int i=1;i<size-1;i++){
			for(int j=1;j<size-1;j++){
				data[i][j] = r.nextFloat()*2-1;
			}
		}
	}
	
	public HeightMap(int size){
		data = new float[size][size];
	}
	
	public HeightMap(int size, float value){
		data = new float[size][size];
		
		for(int i=0;i<size;i++){
			for(int j=0;j<size;j++){
				data[i][j] = value;
			}
		}
	}
	
	public void diffuse(int passes){
		float[][] tmp = new float[data.length][data.length];
		float[][] tmp2;
		
		for(int i=0;i<data.length;i++){
			tmp[i][0] = data[i][0];
			tmp[i][data.length-1] = data[i][data.length-1];
			tmp[0][i] = data[0][i];
			tmp[data.length-1][i] = data[data.length-1][i];
		}
		
		for(int k = 0;k<passes;k++){
			for(int i=1;i<data.length-1;i++){
				for(int j=1;j<data.length-1;j++){
					tmp[i][j] = (data[i-1][j]+data[i+1][j]+data[i][j+1]+data[i][j-1])/4;
					}
			}
			tmp2 = data;
			data = tmp;
			tmp = tmp2;
		}
	}
	
	public HeightMap extractCenter(int subSize, int indent){
		HeightMap ret = new HeightMap(subSize);
		float offset = indent/(float)(data.length+0.5f);
		float stretch = (1-2*offset)/((float)subSize);//data.length/((float)subSize*subSize);
		
		
		for(int i=0;i<subSize;i++){
			for(int j=0;j<subSize;j++){
				//System.out.println((offset+i*stretch)+"/"+(offset+j*stretch));
				ret.data[i][j] = interpolate(offset+i*stretch,offset+j*stretch);
				//System.out.println("val = "+ret.data[i][j]);
			}
		}
		
		//System.out.println("offset="+offset);
		//System.out.println();
		
		return ret;
	}
	
	public HeightMap stretch(int newSize){
		HeightMap ret = new HeightMap(newSize);

		for(int i=1;i<newSize-1;i++){
			for(int j=1;j<newSize-1;j++){
				ret.data[i][j] = interpolate(i/(float)newSize,j/(float)newSize);
			}
		}
		
		return ret;
	}
	
	public float interpolate(float x, float y){
		x*= (data.length-1);
		y*= (data.length-1);
		
		int ix = (int)x, 
		    iy = (int)y;
		
		x -= (float) Math.floor(x);
		y -= (float) Math.floor(y);
		
		float f1 = data[ix][iy] * (1-x) + x * data[ix+1][iy],
		      f2 = data[ix][iy+1] * (1-x) + x * data[ix+1][iy+1];
		
		return f1 * (1-y) + y * f2;
	}
	
	public void scaleTo(float min, float max){
		float cmin=data[0][0], cmax=data[0][0];
		
		//find min/max
		for(int i=0;i<data.length;i++){
			for(int j=0;j<data.length;j++){
				if(data[i][j]<cmin)
					cmin = data[i][j];
				if(data[i][j]>cmax)
					cmax = data[i][j];
			}
		}
		
		float scale = (max-min)/(cmax-cmin);
		//rescale
		for(int i=0;i<data.length;i++){
			for(int j=0;j<data.length;j++){
				data[i][j] = (data[i][j] - cmin)*scale+min;
			}
		}
	}
	
	public void add(float value){
		for(int i=0; i<data.length;i++){
			for(int j=0; j<data.length;j++){
				data[i][j]+=value;
			}
		}
	}
	
	public void scale(float value){
		for(int i=0; i<data.length;i++){
			for(int j=0; j<data.length;j++){
				data[i][j]*=value;
			}
		}
	}
	
	public void add(HeightMap toAdd, int offsetx, int offsetz){
		if(offsetx<0||offsetx+toAdd.data.length>data.length||
				offsetz<0||offsetz+toAdd.data.length>data.length){
			throw new RuntimeException("Invalid offset: "+offsetx+"/"+offsetz);
		}
		
		for(int i=0; i<toAdd.data.length;i++){
			for(int j=0; j<toAdd.data.length;j++){
				data[i+offsetx][j+offsetz]+=toAdd.data[i][j];
			}
		}
	}
}